import { urlEncodeValue } from "../helper.ts";
import { FieldParam, FieldTupleParam } from "../main.ts";
import { Handler } from "./index.ts";

export class NValueHandler implements Handler {
  check<T, Extra>(param: FieldParam<T, Extra>): void {
    if (!(param.value instanceof Array) || param.value.length <= 1) {
      throw new Error(`${String(param.op)}'s value length must greater then 1`);
    }
  }

  process<T, Extra>(param: FieldParam<T, Extra>, group?: string): string {
    if (!(param.value instanceof Array)) return "";
    let str = "";
    if (group) {
      str = `${group}.${String(param.label)}-op=${param.op}`;
      param.value.forEach((v, i) => {
        str += "&" +
          `${group}.${String(param.label)}-${i}=${urlEncodeValue(v)}`;
      });
    } else {
      str = `${String(param.label)}-op=${param.op}`;
      param.value.forEach((v, i) => {
        str += "&" + `${String(param.label)}-${i}=${urlEncodeValue(v)}`;
      });
    }

    return str;
  }

  processTuple<T, Extra>(
    param: FieldTupleParam<T, Extra>,
    group?: string,
  ): string {
    if (!(param[2] instanceof Array)) return "";
    let str = "";
    if (group) {
      str = `${group}.${String(param[0])}-op=${param[1]}`;
      param[2].forEach((v, i) => {
        str += "&" + `${group}.${String(param[0])}-${i}=${urlEncodeValue(v)}`;
      });
    } else {
      str = `${String(param[0])}-op=${param[1]}`;
      param[2].forEach((v, i) => {
        str += "&" + `${String(param[0])}-${i}=${urlEncodeValue(v)}`;
      });
    }

    return str;
  }

  checkTuple<T, Extra>(param: FieldTupleParam<T, Extra>): void {
    if (!(param[2] instanceof Array) || param[2].length <= 1) {
      throw new Error(`${String(param[1])}'s value length must greater then 1`);
    }
  }

  processObj<T, Extra>(
    obj: object,
    param: FieldParam<T, Extra>,
    group?: string,
  ): void {
    if (!(param.value instanceof Array)) return;
    if (group) {
      Object.assign(obj, { [`${group}.${param.label}-op`]: param.op });
      param.value.forEach((v, i) => {
        Object.assign(obj, {
          [`${group}.${param.label}-${i}`]: urlEncodeValue(v),
        });
      });
    } else {
      Object.assign(obj, { [`${param.label}-op`]: param.op });
      param.value.forEach((v, i) => {
        Object.assign(obj, {
          [`${param.label}-${i}`]: urlEncodeValue(v),
        });
      });
    }
  }

  processObjTuple<T, Extra>(
    obj: object,
    param: FieldTupleParam<T, Extra>,
    group?: string,
  ): void {
    if (!(param[2] instanceof Array)) return;
    if (group) {
      Object.assign(obj, { [`${group}.${param[0]}-op`]: param[1] });
      param[2].forEach((v, i) => {
        Object.assign(obj, {
          [`${group}.${param[0]}-${i}`]: urlEncodeValue(v),
        });
      });
    } else {
      Object.assign(obj, { [`${param[0]}-op`]: param[1] });
      param[2].forEach((v, i) => {
        Object.assign(obj, {
          [`${param[0]}-${i}`]: urlEncodeValue(v),
        });
      });
    }
  }
}
